#!/bin/bash
#set -x
# while read line;do
#     eval "$line"
# done < ./build.conf
# id=`sed '/^ID=/!d;s/.*=//' urfile`
# source ./auto_build.conf
######################################################
# Common variables
######################################################
WORK_PATH=$(readlink -f ${0} | xargs dirname)
script_name=$(basename $0)
script_param=$@
cfg_file=${WORK_PATH}/.${script_name%\.*}.conf
source ${cfg_file}
lock_file="${WORK_PATH}/.${script_name%\.*}.lock"
log_dir="${WORK_PATH}/log/$(date +%Y%m%d)"
log="${log_dir}/${script_name%\.*}_${script_param// /_}.log"
build_mkdocs_log="${log_dir}/$(date +%Y%m%d%H%M%S)_build_mkdocs.log"

######################################################
# Common function
######################################################
function usage
{
    echo "Usage: $(basename $0) command"
    echo "command:"
    echo "    help             Show list of command-line options."
    echo "    init             Initialize the build environment."
    echo "    build-capnp      Build capnp files to markdown files using capnp."
    echo "    build            Build markdown files to html files using mkdocs."
    echo "    commit           Commit mkdocs built result to mkdocs-review server."
    
    echo "    update           Update source code."
    echo "    mapping          Create soft link of the source directory to mkdocs"
    echo "    unmapping        Delete soft link of the source directory to mkdocs"
    echo "    convert          Convert link of the markdown."
    echo "    reset            Reset the build environment."
    echo ""
}
function start_execute
{
    if [[ -e ${lock_file} ]]; then
        echo "[ERR ] Others are using the current environment."
        exit 1
    else
        # create lock file
        touch ${lock_file}
        #  init log file
        if [[ -e ${log_dir} ]]; then
            :> ${log}
        else
            mkdir -p ${log_dir}
            :> ${log}
        fi
        echo "######################################################"            | tee -a ${log}
        echo "[INFO] Start execute command : ${script_name} ${script_param}"     | tee -a ${log}
        echo "######################################################"            | tee -a ${log}
        cd ${WORK_PATH}
        if [[ $? -ne 0 ]]; then
            exit 1
        fi
    fi
}
function normal_exit
{
    # delete lock file.
    if [[ -e ${lock_file} ]]; then
        rm -fr ${lock_file}
    fi
    echo "######################################################"                | tee -a ${log}
    echo  "[INFO] Successfully execute command : ${script_name} ${script_param}" | tee -a ${log}
    echo "######################################################"                | tee -a ${log}
    cd ${WORK_PATH}
    exit 0
}
function abnormal_exit
{
    # delete lock file.
    if [[ -e ${lock_file} ]]; then
        rm -fr ${lock_file}
    fi
    echo "######################################################"                | tee -a ${log}
    echo  "[ERR ] Failed to execute command : ${script_name} ${script_param}"    | tee -a ${log}
    echo "######################################################"                | tee -a ${log}
    cd ${WORK_PATH}
    exit 1
}

######################################################
# Git clone and update function
#
# @function   git_clone_update
# @param      1:git_repo_url
# @param      2:git_repo_name
# @param      3:git_repo_branch
# @param      4:git_repo_branch_commitid
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function git_clone_update
{
    local git_repo_url=$1
    local git_repo_name=$2
    local git_repo_branch=$3
    local git_repo_branch_commitid=$4
    echo "------------------------------------------------------"               >> ${log}
    echo "[INFO] Start update ${git_repo_name} from ${git_repo_url}"            >> ${log}
    # echo "------------------------------------------------------"               >> ${log}

    if [[ ${git_repo_url} != "" ]] && [[ ${git_repo_name} != "" ]] && [[ ${git_repo_branch} != "" ]]; then
        # git pull
        if [[ -e ${git_repo_name}/.git ]] ;then
            cd ${git_repo_name}
            # reset branch
            git reset --hard HEAD    >> ${log} 2>&1
            git clean -df            >> ${log} 2>&1
            if [[ $? -ne 0 ]]; then
                echo "[ERR ] Failed to git clean branch." >> ${log}
                return 1
            fi

            # switch default branch
            local default_branch=$(git branch -r --points-at refs/remotes/origin/HEAD | grep '\->' | cut -d' ' -f5 | cut -d/ -f2)
            if [[ $(git rev-parse --abbrev-ref HEAD) != "${default_branch}" ]]; then
                git switch ${default_branch}    >> ${log} 2>&1
                if [[ $? -ne 0 ]]; then
                    echo "[ERR ] Failed to switch default branch =>${default_branch}" >> ${log}
                    return 1
                fi
            fi

            # delete other local branch
            git branch -D $(git branch -l |grep -v ${default_branch})    >> ${log} 2>&1
            # sync remote branch name
            git remote prune origin                                      >> ${log} 2>&1
            
            # update all branch
            git pull     >> ${log} 2>&1
            if [[ $? -ne 0 ]]; then
                echo "[ERR ] Failed to git pull branch." >> ${log}
                return 1
            fi
        # git clone
        else
            # clone repository
            rm -fr ${git_repo_name}
            echo "Cloning into ${git_repo_name} ..."    >> ${log}
            git clone --progress ${git_repo_url} ${git_repo_name} 2> ${log_dir}/.git_progress.log 1>> ${log}
            if [[ $? -ne 0 ]]; then
                echo "[ERR ] Failed to git clone repo. repo_url=>${repo_url}"   >> ${log}
                return 1
            fi
            cd ${git_repo_name}
        fi

        # switch branche
        if [[ $(git rev-parse --abbrev-ref HEAD) != "${git_repo_branch}" ]]; then
            git switch ${git_repo_branch}    >> ${log} 2>&1
            if [[ $? -ne 0 ]]; then
                echo "[ERR ] Failed to git switch branch. branch=>${git_repo_branch}" >> ${log}
                return 1
            fi
        fi

        # reset commit id
        if [[ ${git_repo_branch_commitid} != "" ]];then
            echo "[INFO] Exec command=>$ git reset --hard ${git_repo_branch_commitid}"
            git reset --hard ${git_repo_branch_commitid}
            if [[ $? -ne 0 ]]; then
                echo "[ERR ] Failed to git reset --hard ${git_repo_branch_commitid}" >> ${log}
                return 1
            fi
        fi
        cd - >/dev/null
    else
        echo "[ERR ] Failed to update ${git_repo_name}:${git_repo_branch} from ${git_repo_url}"   >> ${log}
        return 1
    fi
    # echo "------------------------------------------------------"               >> ${log}
    echo "[INFO] Successfully update ${git_repo_name} from ${git_repo_url}"     >> ${log}
    echo "------------------------------------------------------"               >> ${log}
    # echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Upgrade capnp build docker.
#
# @function   upgrade_capnp_build_docker
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function upgrade_capnp_build_docker
{
    # switch path
    local capnp_build_tool_abs_path="${WORK_PATH}/${CAPNP_BUILD_TOOL_SAVE_PATH#*./}"
    local capnp_build_tool_parent_path=$(dirname ${capnp_build_tool_abs_path})
    local capnp_build_tool_name=$(basename ${capnp_build_tool_abs_path})
    if [[ ! -e ${capnp_build_tool_parent_path} ]]; then
        mkdir -p ${capnp_build_tool_parent_path}
        cd ${capnp_build_tool_parent_path}
    else
        cd ${capnp_build_tool_parent_path}
    fi

    # update capnp build tool
    git_clone_update ${CAPNP_BUILD_TOOL_GIT_URL} ${capnp_build_tool_name} ${CAPNP_BUILD_TOOL_GIT_BRANCH}
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to update capnp build tool from ${CAPNP_BUILD_TOOL_GIT_URL}"   >> ${log}
        echo "------------------------------------------------------"                      >> ${log}
        return 1
    fi

    # get current commit id of the capnp build tool.
    cd ${capnp_build_tool_abs_path}
    local capnp_build_tool_current_commitid=$(git rev-parse HEAD)
    # reset path 
    cd ${WORK_PATH}
    

    # Upgrade capnp build docker
    echo "======================================================"               >> ${log}
    echo "[INFO] Start upgrade capnp build docker."                             >> ${log}
    # echo "======================================================"               >> ${log}
    if [[ "${CAPNP_BUILD_TOOL_GIT_COMMITID}" != ${capnp_build_tool_current_commitid} ]]; then 
        echo "[INFO] The capnp build docker needs to be upgraded."    >> ${log} 
        local backup_abs_path=${WORK_PATH}/${BACKUP_PATH#*./}
        # Export a container’s filesystem as a tar archive
        {
            while true ; do
                if [[ -e ${WORK_PATH}/log/capnp_status_installed ]]; then
                    local docker_container_id=$(docker ps -f ancestor=${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_BASE_TAG} --format "{{.ID}}")
                    # docker export 
                    echo "[INFO] Export upgraded docker container(${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_BASE_TAG}) to a tar archive."  >> ${log} 
                    rm -fr ${backup_abs_path}/${CAPNP_BUILD_DOCKER_NAME}_${CAPNP_BUILD_DOCKER_TAG}.tar  >> ${log} 2>&1
                    echo ${backup_abs_path}/${CAPNP_BUILD_DOCKER_NAME}_${CAPNP_BUILD_DOCKER_TAG}.tar
                    docker export --output="${backup_abs_path}/${CAPNP_BUILD_DOCKER_NAME}_${CAPNP_BUILD_DOCKER_TAG}.tar" ${docker_container_id}  >> ${log} 2>&1
                    echo "saved" > ${WORK_PATH}/log/capnp_status_saved
                    break
                fi
                sleep 1
            done
        } &

        # upgrade capnp build tool
        echo "[INFO] Upgrade capnp build tool in the capnp build docker container(${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_BASE_TAG})."    >> ${log}
        local cpu_num="$(cat /proc/cpuinfo | grep processor | wc -l)"
        docker run --rm -it -v ~:/home/hosthome:ro -v $(pwd):/workdir --name poky-$(id -un)-shenchh --workdir=/workdir \
            ${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_BASE_TAG} \
                bash -c "cd ${CAPNP_BUILD_TOOL_SAVE_PATH} ;\
                    rm -fr tmp_build ;\
                    mkdir -p tmp_build ;\
                    cd tmp_build ;\
                    echo '$ cmake ..' ;\
                    cmake .. ;\
                    echo '$ sudo make -j ${cpu_num} install' ; \
                    sudo make -j ${cpu_num} install ;\
                    cd .. ;\
                    capnp compile -o md-docs sample.capnp ;\
                    rm -fr json_output md_output tmp_build ;\
                    echo installed > /workdir/log/capnp_status_installed ;\
                    sleep 5 ;\
                    while true ; do if [[ -e /workdir/log/capnp_status_saved ]]; then rm -fr /workdir/log/capnp_status_*; exit; fi; sleep 1; done ;\
                " > ${log_dir}/capnp_build_tool_upgrade.log 2>&1 
        if [[ $? -ne 0 ]]; then
            echo "[ERR ] Failed to upgrade capnp build tool!"     >> ${log}
            return 1
        fi

        # delete current docker image
        local docker_image_id=$(docker images ${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_TAG} --format "{{.ID}}")
        if [[ -n ${docker_image_id} ]]; then
            echo "[INFO] Delete old docker image ${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_TAG}."    >> ${log}
            docker rmi -f ${docker_image_id} >> ${log} 2>&1
            if [[ $? -ne 0 ]]; then
                echo "[ERR ] Failed to delete current docker image!"     >> ${log}
                return 1
            fi
        fi 
        # import docker image from a tar archive
        echo "[INFO] Import new docker image ${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_TAG}."    >> ${log}
        docker import "${backup_abs_path}/${CAPNP_BUILD_DOCKER_NAME}_${CAPNP_BUILD_DOCKER_TAG}.tar"  ${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_TAG} >> ${log} 2>&1
        if [[ $? -ne 0 ]]; then
            echo "[ERR ] Failed to import docker image!"     >> ${log}
            return 1
        fi
        # update config file 
        sed -ri "s/(^CAPNP_BUILD_TOOL_GIT_COMMITID)=.*$/\1=${capnp_build_tool_current_commitid}/g" ${cfg_file}

    else
        echo "[INFO] The cpanp docker doesn't need to be upgraded."             >> ${log}
    fi 

    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully upgrade capnp build docker."                      >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Upgrade build environment of the mkdocs
#
# @function   upgrade_mkdocs
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function upgrade_mkdocs_build_env
{
    # check mkdocs build environment
    echo "======================================================"               >> ${log}
    echo "[INFO] Start check mkdocs build environment."                         >> ${log}
    local target_mkdoc_ver=$(curl -s --connect-timeout 10 ${MKDOCS_RELEASE_URL} |grep 'name="generator"' | cut -d '=' -f 3| sed  's/["> ]//g'| cut -d ',' -f 1 )
    local target_mkdoc_material_ver=$(curl -s --connect-timeout 10 ${MKDOCS_RELEASE_URL} |grep 'name="generator"' | cut -d '=' -f 3| sed  's/["> ]//g'| cut -d ',' -f 2 )
    if [[ ${MKDOCS_BUILD_TYPE} == "docker" ]]; then
        {
            while true ; do
                if [[ -e ${WORK_PATH}/log/mkdocs_env_status_upgraded ]]; then
                    # docker container commit
                    local docker_container_id=$(docker ps -f ancestor=${MKDOCS_BUILD_DOCKER_IMAGE}:${MKDOCS_BUILD_DOCKER_TAG} --format "{{.ID}}")
                    docker commit ${docker_container_id} ${MKDOCS_BUILD_DOCKER_IMAGE}:${MKDOCS_BUILD_DOCKER_TAG} >> ${log} 2>&1
                    echo "commit" > ${WORK_PATH}/log/mkdocs_env_status_commited
                    break
                elif [[ -e ${WORK_PATH}/log/mkdocs_env_status_not_upgraded ]]; then
                    echo "not commit" > ${WORK_PATH}/log/mkdocs_env_status_commited
                    break
                fi
                sleep 1
            done
        } &

        docker run --rm -it  -e http_proxy=${http_proxy} -e https_proxy=${https_proxy} -e no_proxy=${no_proxy} -v ~:/home/hosthome:ro -v $(pwd):/workdir \
            --name poky-$(id -un)-docs-tool  --workdir=/workdir ${MKDOCS_BUILD_DOCKER_IMAGE}:${MKDOCS_BUILD_DOCKER_TAG} \
            bash -c "if  pip list --format=columns |grep  'mkdocs ' | grep -v grep| grep ${target_mkdoc_ver##*-} >/dev/null ; then \
                        echo [INFO] No need to upgrade mkdocs; \
                    else \
                        echo [WARN] Upgrade mkodcs; \
                        pip install mkdocs==${target_mkdoc_ver##*-} && \
                        echo upgraded > /workdir/log/mkdocs_env_status_upgraded ; \
                    fi ;\
                    if  pip list --format=columns |grep  'mkdocs-material ' | grep -v grep| grep ${target_mkdoc_material_ver##*-} >/dev/null ; then \
                        echo [INFO] No need to upgrade mkdocs-material; \
                    else \
                        echo [WARN] Upgrade mkdocs-material; \
                        pip install mkdocs-material==${target_mkdoc_material_ver##*-} && \
                        echo upgraded > /workdir/log/mkdocs_env_status_upgraded ;\
                    fi ;\
                    if [[ ! -e ${WORK_PATH}/log/mkdocs_env_status_upgraded ]]; then \
                        echo upgraded > /workdir/log/mkdocs_env_status_not_upgraded ;\
                    fi ;\
                    sleep 5 ;\
                    while true ; do if [[ -e /workdir/log/mkdocs_env_status_commited ]]; then rm -fr /workdir/log/mkdocs_env_status_*; exit; fi; sleep 1; done ;\
                " >> ${log} 2>&1
    else
        if  pip list --format=columns |grep  'mkdocs ' | grep -v grep| grep ${target_mkdoc_ver##*-} >/dev/null ; then 
            echo "[INFO] No need to upgrade mkdocs"  >> ${log}
        else 
            echo "[WARN] Upgrade mkodcs"  >> ${log}
            pip install mkdocs==${target_mkdoc_ver##*-} >> ${log} 2>&1
        fi

        if  pip list --format=columns |grep  'mkdocs-material ' | grep -v grep| grep ${target_mkdoc_material_ver##*-} >/dev/null ; then 
            echo "[INFO] No need to upgrade mkdocs-material"  >> ${log}
        else 
            echo "[WARN] Upgrade mkodcs-material"  >> ${log}
            pip install mkdocs==${target_mkdoc_material_ver##*-} >> ${log} 2>&1
        fi
    fi
    echo "[INFO] Successfully check mkdocs build environment."            >> ${log}
    echo "======================================================"         >> ${log}
    echo ""                                                               >> ${log}

    # switch directory
    local mkdocs_abs_path="${WORK_PATH}/${MKDOCS_PATH#*./}"
    local repo_name=$(basename ${mkdocs_abs_path})
    if [[ ! -e $(dirname ${mkdocs_abs_path}) ]]; then
        mkdir -p $(dirname ${mkdocs_abs_path})
        cd $(dirname ${mkdocs_abs_path})
    else
        cd $(dirname ${mkdocs_abs_path})
    fi

    # update build tool mkdocs
    echo "======================================================"               >> ${log}
    echo "[INFO] Start upgrade build tool of the mkdocs."                       >> ${log}
    # echo "======================================================"               >> ${log}
    git_clone_update ${MKDOCS_GIT_URL} ${repo_name} ${MKDOCS_GIT_BRANCH}
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to upgrade build tool of the mkdocs from ${MKDOCS_GIT_URL}"   >> ${log}
        echo "------------------------------------------------------"                            >> ${log}
        return 1
    fi

    # reset path
    cd ${WORK_PATH}
    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully upgrade build tool of the mkdocs."                >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Delete invalid source code
#
# @function   delete_invalid_source
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function delete_invalid_source
{
    echo "======================================================"               >> ${log}
    echo "[INFO] Start delete invalid source code."                             >> ${log}
    # echo "======================================================"               >> ${log}
    if [[ -e ${SRC_SAVE_PATH} ]]; then
        # switch directory
        cd ${SRC_SAVE_PATH}
        for dir_name in $(ls); do
            if [[ -e ./${dir_name}/.git ]] && [[ ! "${REPO_BRANCHES[@]}" =~ "${dir_name}" ]]; then
                rm -fr ${dir_name}    >> ${log} 2>&1
                if [[ $? -ne 0 ]]; then
                    echo "[ERR ] Failed to delete invalid source code. directory=>${dir_name}" >> ${log}
                    return 1
                fi
            fi
        done
        # reset path
        cd ${WORK_PATH}
    fi
    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully delete invalid source code."                      >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Update source code
#
# @function   update_source
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function update_source
{
    echo "======================================================"       >> ${log}
    echo "[INFO] Start update source code."                             >> ${log}
    # echo "======================================================"       >> ${log}
    # switch directory
    if [[ -e ${SRC_SAVE_PATH} ]]; then
        cd ${SRC_SAVE_PATH}
    else
        mkdir -p ${SRC_SAVE_PATH}
        cd ${SRC_SAVE_PATH}
    fi

    # update all git branch
    for repo_branch in ${REPO_BRANCHES[@]}; do
        local tmp_array=(${repo_branch//:/ })
        local group_name=${tmp_array[0]}
        local repo_name=${tmp_array[1]}
        local branch_name=${tmp_array[2]}
        local commit_id=${tmp_array[3]}
        local repo_url="${GIT_URL}/${group_name}/${repo_name}.git"
        git_clone_update ${repo_url} ${repo_name} ${branch_name} ${commit_id}
        if [[ $? -ne 0 ]]; then
            echo "[ERR ] Failed to update ${repo_name} from ${repo_url}"    >> ${log}
            echo "------------------------------------------------------"   >> ${log}
            return 1
        fi
    done

    # reset path
    cd ${WORK_PATH}
    # echo "======================================================"       >> ${log}
    echo "[INFO] Successfully update source code."                      >> ${log}
    echo "======================================================"       >> ${log}
    echo ""                                                             >> ${log}
    return 0
}


######################################################
# Init build environment.
#
# @function   init_build_env
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function init_build_env
{
    #Upgrade capnp build docker.
    upgrade_capnp_build_docker
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to upgrade capnp build docker."                     >> ${log}
        echo "======================================================"           >> ${log}
        return 1
    fi

    # Upgrade build environment of the mkdocs
    upgrade_mkdocs_build_env
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to upgrade build environment of the mkdocs."        >> ${log}
        echo "======================================================"           >> ${log}
        return 1
    fi

    # delete invalid source code
    delete_invalid_source
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to delete invalid source code."                     >> ${log}
        echo "======================================================"           >> ${log}
        return 1
    fi

    # update source code
    update_source
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to update source code."                             >> ${log}
        echo "======================================================"           >> ${log}
        return 1
    fi

    return 0
}

######################################################
# Reset build environment.
#
# @function   reset_build_env
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function reset_build_env
{
    echo "======================================================"               >> ${log}
    echo "[INFO] Start reset build environment."                                >> ${log}
    # echo "======================================================"               >> ${log}

    local mkdocs_abs_path="${WORK_PATH}/${MKDOCS_PATH#*./}"
    if [[ -e ${mkdocs_abs_path} ]]; then
        # switch path
        cd ${mkdocs_abs_path}
        # reset build env
        git reset --hard HEAD    >> ${log} 2>&1
        git clean -df            >> ${log} 2>&1 
        if [[ $? -ne 0 ]]; then
            cd ${WORK_PATH}
            echo "[ERR ] Failed to git clean branch."      >> ${log}
            return 1
        fi
        # reset path
        cd ${WORK_PATH}
    else
        echo "[ERR ] The build environment does not exist." >> ${log}
        return 1
    fi

    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully reset build environment."                         >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Build capnp files to markdown files using capnp.
#
# @function   build_capnp
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function build_capnp
{
    echo "======================================================"               >> ${log}
    echo "[INFO] Start build capnp files to markdown files using capnp."        >> ${log}
    # echo "======================================================"               >> ${log}

    # build capnp files to markdown files
    for capnp_build_path_and_cmd in ${CAPNP_BUILD_PATH_AND_CMD[@]} ; do
        local repo_name=$(echo ${capnp_build_path_and_cmd} | cut -d : -f 1)
        local build_path=$(echo ${capnp_build_path_and_cmd} | cut -d : -f 2)
        local cmd_type=$(echo ${capnp_build_path_and_cmd} | cut -d : -f 3)
        local cmd=$(echo ${capnp_build_path_and_cmd} | cut -d : -f 4)
        local repo_src_abs_path=$(dirname ${WORK_PATH}/${build_path#*./})

        if [[ -e ${repo_src_abs_path} ]] ; then

            docker run --rm -it -v ~:/home/hosthome:ro -v $(pwd):/workdir --name poky-$(id -un)-shenchh --workdir=/workdir \
                ${CAPNP_BUILD_DOCKER_NAME}:${CAPNP_BUILD_DOCKER_TAG} \
                    bash -c "cd ${build_path} ;\
                        if [[ ${cmd_type} == 'shell' ]] ; then bash ${cmd} ; else ${cmd}; fi ;\
                        cd .. ;\
                        chown -R 1002:1002 docs build ;\
                    exit" > ${log_dir}/build_capnp.log
        
            if [[ $?  -ne 0 ]]; then
                echo "[ERR ] # Failed to build capnp files to markdown files using capnp." >> ${log}
                return 1
            fi
        else
            echo "[ERR ] The capnp file path [${capnp_src_abs_path}] does not exist!"       >> ${log}
            return 1
        fi
    done

    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully build capnp files to markdown files using capnp." >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Delete soft link of the source directory to mkdocs
#
# @function   delete_soft_link
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function delete_soft_link
{
    echo "======================================================"               >> ${log}
    echo "[INFO] Start delete soft link of the source directory to mkdocs."     >> ${log}
    # echo "======================================================"               >> ${log}
    for delete_path in ${DELETE_REPO_MAP_PATH[@]}; do
        local abs_path="${WORK_PATH}/${delete_path#*./}"
        if [[ -e  ${abs_path} ]]; then
            rm -fr ${abs_path} >> ${log} 2>&1
            if [[ $? -ne 0 ]]; then
                echo "[ERR ] Failed to delete soft link of the source directory to mkdocs. link=>${abs_path}" >> ${log}
                return 1
            fi
        fi
    done
    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully delete soft link of the source directory to mkdocs." >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Create soft link of the source directory to mkdocs
#
# @function   create_soft_link
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function create_soft_link
{
    echo "======================================================"               >> ${log}
    echo "[INFO] Start create soft link of the source directory to mkdocs."     >> ${log}
    # echo "======================================================"               >> ${log}
    for repo_map_path in ${REPO_MAP_PATH[@]}; do
        local repo_name=$(echo ${repo_map_path} | cut -d : -f 1)
        local sub_path=$(echo ${repo_map_path} | cut -d : -f 2)
        local map_path=$(echo ${repo_map_path} | cut -d : -f 3)
        local abs_src_path="${WORK_PATH}/${SRC_SAVE_PATH#*./}/${repo_name}"
        local abs_map_path="${WORK_PATH}/${map_path#*./}/${repo_name}"
        local repo_unit_list=(${REPO_MAP_UNITS[${repo_name}]})
        # echo $abs_src_path
        # echo $abs_map_path

        # create soft link
        for unit in ${repo_unit_list[@]}; do
            if [[ "$unit" == "all" ]]; then
                if [[ ! -e $(dirname ${abs_map_path}) ]]; then
                    mkdir -p $(dirname ${abs_map_path})
                    cd $(dirname ${abs_map_path})
                else
                    cd $(dirname ${abs_map_path})
                fi
                if [[ -e ${abs_src_path} ]] && [[ ! -e ${repo_name} ]]; then
                    if [[ ${MKDOCS_BUILD_TYPE} == "docker" ]]; then
                        cp -rf ${abs_src_path} .
                    else
                        ln -s ${abs_src_path}
                    fi
                else
                    echo "[WARN] The path ${abs_src_path} does not exist."
                fi
                cd - 2>&1 >/dev/null
                break
            elif [[ "$unit" != "" ]]; then
                if [[ ! -e ${abs_map_path}/${sub_path} ]]; then
                    mkdir -p ${abs_map_path}/${sub_path}
                    cd ${abs_map_path}/${sub_path}
                else
                    cd ${abs_map_path}/${sub_path}
                fi
                if [[ -e ${abs_src_path}/${sub_path:='.'}/${unit} ]]; then
                    if [[ ${MKDOCS_BUILD_TYPE} == "docker" ]]; then
                        cp -rf ${abs_src_path}/${sub_path:='.'}/${unit} .
                        # ln -s ${abs_src_path}/${sub_path:='.'}/${unit}
                    else
                        ln -s ${abs_src_path}/${sub_path:='.'}/${unit}
                    fi
                else
                    echo "[WARN] The path ${abs_src_path}/${sub_path:='.'}/${unit} does not exist."
                fi
                cd - 2>&1 >/dev/null
            else
                echo "The ${repo_name} does not need to create soft link." >> ${log}
            fi
        done
    done

    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully create soft link of the source directory to mkdocs." >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}


######################################################
# Build markdown files to html files using mkdocs.
#
# @function   build_mkdocs
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function build_mkdocs
{
    # Delete soft link of the source directory to mkdocs
    delete_soft_link
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to delete soft link of the source directory to mkdocs." >> ${log}
        echo "======================================================"               >> ${log}
        return 1
    fi
    # Create soft link of the source directory to mkdocs
    create_soft_link
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to create soft link of the source directory to mkdocs." >> ${log}
        echo "======================================================"               >> ${log}
        return 1
    fi

    # Build markdown files to html files using mkdocs.
    echo "======================================================"               >> ${log}
    echo "[INFO] Start build markdown files to html files using mkdocs."        >> ${log}
    # echo "======================================================"               >> ${log}
    local mkdocs_abs_path="${WORK_PATH}/${MKDOCS_PATH#*./}"
    if [[ -e ${mkdocs_abs_path} ]]; then
        # switch path
        cd ${mkdocs_abs_path}
        rm -fr ${mkdocs_abs_path}/site/* >> ${log} 2>&1
        local ret_code=0
        if [[ ${MKDOCS_BUILD_TYPE} == "docker" ]]; then
            # docker run -v $(pwd):/mkdocs -e LANG=C.UTF-8 ${MKDOCS_BUILD_DOCKER_IMAGE}:${MKDOCS_BUILD_DOCKER_TAG} mkdocs build -f /mkdocs/mkdocs.yml  > ${log_dir}/build_mkdocs.log 2>&1
            # ret_code=$?
            # docker run -v $(pwd):/mkdocs -e LANG=C.UTF-8 ${MKDOCS_BUILD_DOCKER_IMAGE}:${MKDOCS_BUILD_DOCKER_TAG} chown -R 1002:1002 /mkdocs/site >> ${log_dir}/build_mkdocs.log 2>&1
            # if [[ ${ret_code}  -eq 0 ]]; then
            #     ret_code=$?
            # fi
            docker run --rm -it -v ~:/home/hosthome:ro -v $(pwd):/mkdocs -e LANG=C.UTF-8 --name poky-$(id -un)-mkdocs-tool \
                --workdir=/mkdocs ${MKDOCS_BUILD_DOCKER_IMAGE}:${MKDOCS_BUILD_DOCKER_TAG} \
                bash -c "cd /mkdocs && \
                    ./build.sh clean && \
                    ./build.sh build ; \
                    chown -R 1002:1002 ./site && \
                    exit 0;" > ${build_mkdocs_log} 2>&1
            ret_code=$?
        else
            ./build.sh build 2>&1 > ${log_dir}/build_mkdocs.log 2>&1
            ret_code=$?
        fi
        # reset path
        cd - 2>&1 >/dev/null
        if [[ ${ret_code}  -ne 0 ]]; then
            echo "[ERR ] # Failed to build markdown files to html files using mkdocs."     >> ${log}
            return 1
        fi
    else
        echo "[ERR ] The markdown file path [${mkdocs_abs_path}] does not exist!"   >> ${log}
        return 1
    fi

    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully build markdown files to html files using mkdocs." >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# Commit mkdocs built result to mkdocs-review server.
#
# @function   commit_review
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function commit_review
{
    # switch path
    local mkdocs_review_abs_path="${WORK_PATH}/${MKDOCS_REVIEW_PATH#*./}"
    if [[ ! -e $(dirname ${mkdocs_review_abs_path}) ]]; then
        mkdir -p $(dirname ${mkdocs_review_abs_path})
        cd $(dirname ${mkdocs_review_abs_path})
    else
        cd $(dirname ${mkdocs_review_abs_path})
    fi

    # update mkdocs-review
    git_clone_update ${MKDOCS_REVIEW_GIT_URL} $(basename ${mkdocs_review_abs_path}) ${MKDOCS_REVIEW_GIT_BRANCH}
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to update mkdocs-review from ${MKDOCS_REVIEW_GIT_URL}"  >> ${log}
        echo "------------------------------------------------------"               >> ${log}
        return 1
    fi

    # commit built result to mkdocs-review server.
    echo "======================================================"               >> ${log}
    echo "[INFO] Start commit mkdocs built result to mkdocs-review server."     >> ${log}
    # echo "======================================================"               >> ${log}
    local mkdocs_abs_path="${WORK_PATH}/${MKDOCS_PATH#*./}"
    if [[ -e ${mkdocs_abs_path} ]]; then
        # copy build result to mkdocs-review server.
        cp -r ${mkdocs_abs_path}/site/* ${mkdocs_review_abs_path}  >> ${log} 2>&1
        if [[ $?  -ne 0 ]]; then
            echo "[ERR ] Failed to exec command [cp -r ${mkdocs_abs_path}/site/* ${mkdocs_review_abs_path}]." >> ${log}
            return 1
        fi
        # git commit change file to mkdocs-review server.
        cd ${mkdocs_review_abs_path}       >> ${log} 2>&1
        git add .                          >> ${log} 2>&1
        git commit -m "modify by tools."   >> ${log} 2>&1
        git push                           >> ${log} 2>&1
        if [[ $?  -ne 0 ]]; then
            echo "[ERR ] Failed to commit mkdocs built result to mkdocs-review server."   >> ${log}
            return 1
        fi

        # reset path
        cd - 2>&1 >/dev/null
    else
        echo "[ERR ] The path [${mkdocs_abs_path}] does not exist!"    >> ${log}
        return 1
    fi

    # reset path
    cd ${WORK_PATH}
    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully commit mkdocs built result to mkdocs-review server."  >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}

    # output confirm address
    echo "Confirm Address: https://github.tmc-stargate.com/pages/peiwen-chen/mkdocs-review/Reference/InterfaceSpec/InterfaceSpec_index/"
    return 0
}


######################################################
# Convert link of the markdown.
#
# @function   reset_build_env
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function convert_markdown
{
    # switch path
    local convert_tool_abs_path="${WORK_PATH}/${CONVERT_TOOL_PATH#*./}"
    if [[ ! -e $(dirname ${convert_tool_abs_path}) ]]; then
        mkdir -p $(dirname ${convert_tool_abs_path})
        cd $(dirname ${convert_tool_abs_path})
    else
        cd $(dirname ${convert_tool_abs_path})
    fi

    # update convert tool
    git_clone_update ${CONVERT_TOOL_GIT_URL} $(basename ${convert_tool_abs_path}) ${CONVERT_TOOL_GIT_BRANCH}
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] Failed to update convert tool from ${CONVERT_TOOL_GIT_URL}"   >> ${log}
        echo "------------------------------------------------------"               >> ${log}
        return 1
    fi

    # convert local link of the markdown
    echo "======================================================"               >> ${log}
    echo "[INFO] Start convert link of the markdown."                           >> ${log}
    # echo "======================================================"               >> ${log}
    for conert_src_path in ${CONVERT_SRC_PATH_LIST[@]}; do
        local conert_src_abs_path="${WORK_PATH}/${conert_src_path#*./}"
        if [[ -e ${conert_src_abs_path} ]] ; then
            cd ${conert_src_abs_path}
            # python ${convert_tool_abs_path}/scripts/mkdocs-conv.py .          >> ${log} 2>&1
            python ${WORK_PATH}/tools/mkdocs-conv.py .                        >> ${log} 2>&1
            cat ./mkdocs-conv* | grep -i error                                >> ${log} 2>&1
            if [[ $? -eq 0 ]]; then
                echo "[ERR ] Failed to convert markdown files."     >> ${log}
                return 1
            fi

            rm -fr *.log   >> ${log} 2>&1
            if [[ $(git status -s | wc -l) -gt 0 ]]; then
                echo "[ERR ] Confirm converted markdown files, file path=> ${conert_src_abs_path}."   >> ${log}
                return 1
            fi
            cd - 2>&1 >/dev/null
        else
            echo "[ERR ] The path [${conert_src_abs_path}] does not exist!"     >> ${log}
            return 1
        fi
    done

    # reset path
    cd ${WORK_PATH}
    # echo "======================================================"               >> ${log}
    echo "[INFO] Successfully convert link of the markdown."                    >> ${log}
    echo "======================================================"               >> ${log}
    echo ""                                                                     >> ${log}
    return 0
}

######################################################
# main
######################################################
if [[ $# -ne 1 ]] ; then
    # echo "Line:${LINENO}"
    echo "[ERR ] Incorrect number of parameters! count=$#" 1>&2
    usage
    exit 1
else
    # start
    start_execute
    case ${1} in
        # "init")
        #     # init build environment
        #     time init_build_env
        #     if [[ $? -ne 0 ]]; then
        #         abnormal_exit
        #     fi 
        #     ;;
        "build-capnp")
            # Build capnp files to markdown files using capnp.
            time build_capnp
            if [[ $? -ne 0 ]]; then
                abnormal_exit
            fi 
            ;;
        "build")
            # Build markdown files to html files using mkdocs.
            time build_mkdocs
            if [[ $? -ne 0 ]]; then
                abnormal_exit
            fi 
            ;;
        # "commit")
        #     # Commit mkdocs built result to mkdocs-review server.
        #     time commit_review
        #     if [[ $? -ne 0 ]]; then
        #         abnormal_exit
        #     fi 
        #     ;;
        # "update")
        #     # git update source code
        #     time update_source
        #     if [[ $? -ne 0 ]]; then
        #         abnormal_exit
        #     fi 
        #     ;;
        # "mapping")
        #     # Delete and create soft link of the source directory to mkdocs
        #     time delete_soft_link && create_soft_link
        #     if [[ $? -ne 0 ]]; then
        #         abnormal_exit
        #     fi 
        #     ;;
        # "unmapping")
        #     # Delete soft link of the source directory to mkdocs
        #     time delete_soft_link
        #     if [[ $? -ne 0 ]]; then
        #         abnormal_exit
        #     fi 
        #     ;;
        # "convert")
        #     # Convert link of the markdown.
        #     time convert_markdown
        #     if [[ $? -ne 0 ]]; then
        #         abnormal_exit
        #     fi 
        #     ;;
        # "reset")
        #     # Reset build environment.
        #     time reset_build_env
        #     if [[ $? -ne 0 ]]; then
        #         abnormal_exit
        #     fi 
        #     ;;
        # "help")
        #     # help info
        #     usage
        #     ;;
        # *)
        #     echo "[ERR ] Parameter command is incorrect! command=${1}" 1>&2
        #     usage
        #     abnormal_exit
        #     ;;
    esac
    normal_exit
fi
